home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Telnet / NCSA / tn3270 2.3d26 source / tn3270 / telnet.c < prev    next >
Text File  |  1991-06-02  |  22KB  |  886 lines

  1. /*
  2.  *  tn3270 for the Macintosh Source Code
  3.  *  Brown University Computing and Information Services
  4.  *  Version 2.3d21, January 17, 1991
  5.  *  Copyright (c) 1988, 1989, 1990, 1991 by Brown University and by
  6.  *  Peter John DiCamillo.
  7.  *
  8.  *  Permission is granted to any individual or institution to use, copy,
  9.  *  or redistribute the binary version of this software and its
  10.  *  documentation provided this notice and the copyright notices are
  11.  *  retained.  Permission is granted to any individual or non-profit
  12.  *  institution to use, copy, modify, or redistribute the source files
  13.  *  of this software provided this notice and the copyright notices are
  14.  *  retained.  This software may not be distributed for profit, either
  15.  *  in original form or in derivative works, nor can the source be
  16.  *  distributed to other than an individual or a non-profit institution.
  17.  *  Any  individual or group interested in seeing and/or using these
  18.  *  source files but who are prevented from doing so by the above
  19.  *  constraints should contact Don Wolfe, Assistant Vice-President for
  20.  *  Computer Systems at Brown University, (401) 863-7250, for possible
  21.  *  software licensing of the source developed at Brown.
  22.  *
  23.  *  Brown University and Peter John DiCamillo make no representations
  24.  *  about the suitability of this software for any purpose.
  25.  *
  26.  *  BROWN UNIVERSITY AND PETER JOHN DICAMILLO GIVE NO WARRANTY, EITHER
  27.  *  EXPRESS OR IMPLIED, FOR THE PROGRAM AND/OR DOCUMENTATION PROVIDED,
  28.  *  INCLUDING, WITHOUT LIMITATION, WARRANTY OF MERCHANTABILITY AND
  29.  *  WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE.
  30.  *  -----------------------------------------------------------------------
  31.  *  The following copyright notice applies to the code in this file for
  32.  *  interpreting the Telnet protocol and performing option negotiations:
  33.  *  -----------------------------------------------------------------------
  34.  *    Copyright (c) 1984-1987 by the Regents of the
  35.  *    University of California and by Gregory Glenn Minshall.
  36.  *
  37.  *    Permission to use, copy, modify, and distribute these
  38.  *    programs and their documentation for any purpose and
  39.  *    without fee is hereby granted, provided that this
  40.  *    copyright and permission appear on all copies and
  41.  *    supporting documentation, the name of the Regents of
  42.  *    the University of California not be used in advertising
  43.  *    or publicity pertaining to distribution of the programs
  44.  *    without specific prior permission, and notice be given in
  45.  *    supporting documentation that copying and distribution is
  46.  *    by permission of the Regents of the University of California
  47.  *    and by Gregory Glenn Minshall.  Neither the Regents of the
  48.  *    University of California nor Gregory Glenn Minshall make
  49.  *    representations about the suitability of this software
  50.  *    for any purpose.  It is provided "as is" without
  51.  *    express or implied warranty.
  52.  */ 
  53.  
  54. #define __SEG__ 3270tcp
  55. #include "maclib.h"
  56. #include "termdef.h"
  57. #include "globals.h"
  58. #define TELCMDS 1
  59. #define TELOPTS 1
  60. #include "telnet.h"
  61. /*
  62.  * Telnet receiver states for fsm
  63.  */
  64. #define    TS_DATA        0
  65. #define    TS_IAC        1
  66. #define    TS_WILL        2
  67. #define    TS_WONT        3
  68. #define    TS_DO        4
  69. #define    TS_DONT        5
  70. /*    #define    TS_CR        6       currently not used */
  71. #define    TS_SB        7        /* sub-option collection */
  72. #define    TS_SE        8        /* looking for sub-option end */
  73.  
  74. short telrcv_state;            /* FSA state */
  75. char data_init;                /* flag for start of new write */
  76. short askedSGA;                /* we have talked about SGA */
  77. char sent3270tt;            /* flag for sent 3270 type */
  78. char hadascii;                /* flag for have had ascii data */
  79. extern char newserver;        /* server which supports new protocol */
  80. extern unsigned char tcphostname[];        /* cshostname, or prompt response */
  81. extern char servermode;        /* for non-terminal server */
  82.  
  83. char hisopts[256];
  84. char myopts[256];
  85.  
  86. static char    doopt[] = { IAC, DO, '%', 'c', 0 };
  87. static char    dont[] = { IAC, DONT, '%', 'c', 0 };
  88. static char    will[] = { IAC, WILL, '%', 'c', 0 };
  89. static char    wont[] = { IAC, WONT, '%', 'c', 0 };
  90.  
  91. static char    subbuffer[100],
  92.         *subpointer, *subend;     /* buffer for sub-options */
  93. #define    SB_CLEAR()    subpointer = subbuffer;
  94. #define    SB_TERM()    subend = subpointer;
  95. #define    SB_ACCUM(c)    if (subpointer < (subbuffer+sizeof(subbuffer))) { \
  96.                 *subpointer++ = (c); \
  97.             }
  98.  
  99. static char    sb_terminal[] = { IAC, SB,
  100.             TELOPT_TTYPE, TELQUAL_IS,
  101.             'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
  102.             IAC, SE };
  103. static char    sb_e_terminal[] = { IAC, SB,
  104.             TELOPT_TTYPE, TELQUAL_IS,
  105.             'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
  106.             '-', 'E',
  107.             IAC, SE };
  108. #define SBTERMTYPE  11
  109. #define    SBTERMMODEL    13
  110.  
  111. static unsigned char showmsg[80];
  112. static char replybuff[100], *replyptr;
  113. static char quitflg = 0;
  114. extern int myport;            /* port for netwrite */
  115. extern char logon;    
  116. extern char pend_conn;
  117. extern unsigned char * wsfbuff;
  118. extern char skiplf, escmode;
  119. extern char tcpinv;            /* tcp pending invldscr */
  120.  
  121. telrcv(sbp, scc)
  122. register unsigned char *sbp;
  123. register short scc;
  124. {
  125. register unsigned char c;
  126. register unsigned char *Sbp;
  127. register short Scc;
  128. short endflg, rc, skipcnt;
  129.  
  130. if (scc <= 0) return;
  131.  
  132. if (cs.dblevel > 2) tcpdump("telrcv", sbp, scc);
  133.  
  134. replyptr = replybuff;
  135.  
  136. while (scc > 0) {
  137.     /*    if (cs.dblevel > 2) {
  138.             sprintf(showmsg, "scc = %d", scc);
  139.             putln(showmsg);
  140.             }    */
  141.     c = *sbp++;
  142.     scc--;
  143.     switch (telrcv_state) {
  144.         case TS_DATA:
  145.             if (c == IAC) {
  146.                 telrcv_state = TS_IAC;
  147.                 continue;
  148.                 }
  149.             Sbp = sbp;
  150.             Scc = scc;
  151.             skipcnt = 0;
  152.             while (Scc > 0) {
  153.                 c = *Sbp++;
  154.                 Scc--;
  155.                 if (c == IAC) {
  156.                     skipcnt++;
  157.                     telrcv_state = TS_IAC;
  158.                     break;
  159.                     }
  160.                 }
  161.             endflg = 0;
  162.             if ((telrcv_state == TS_IAC) && (Scc > 0))
  163.                 if ((*Sbp) == EOR) {
  164.                     skipcnt++;
  165.                     endflg = 1;
  166.                     Sbp++;
  167.                     Scc--;
  168.                     telrcv_state = TS_DATA;
  169.                     }
  170.             tcpdata(sbp-1, scc+1-Scc-skipcnt, data_init, endflg);
  171.             data_init = endflg;
  172.             sbp = Sbp;
  173.             scc = Scc;
  174.             break;
  175.  
  176.         case TS_IAC:
  177.             switch (c) {
  178.                 case WILL:
  179.                     telrcv_state = TS_WILL;
  180.                     continue;
  181.                 case WONT:
  182.                     telrcv_state = TS_WONT;
  183.                     continue;
  184.                 case DO:
  185.                     telrcv_state = TS_DO;
  186.                     continue;
  187.                 case DONT:
  188.                     telrcv_state = TS_DONT;
  189.                     continue;
  190.                 case DM:
  191.                     /*
  192.                      * We may have missed an urgent notification,
  193.                      * so make sure we flush whatever is in the
  194.                      * buffer currently.
  195.                      */
  196.                 /*    SYNCHing = 1;
  197.                     ttyflush();
  198.                     SYNCHing = stilloob(net);
  199.                     settimer(gotDM);            */
  200.                     break;
  201.                 case NOP:
  202.                 case GA:
  203.                     break;
  204.                 case SB:
  205.                     SB_CLEAR();
  206.                     telrcv_state = TS_SB;
  207.                     continue;
  208.                 case EOR:
  209.                     tcpdata(0L, 0, data_init, 1);
  210.                     data_init = 1;
  211.                     break;
  212.                 case IAC:
  213.                     tcpdata(sbp-1, 1, data_init, 0);
  214.                     data_init = 0;
  215.                     break;
  216.                 default:
  217.                     break;
  218.                 }
  219.             telrcv_state = TS_DATA;
  220.             continue;
  221.  
  222.         case TS_WILL:
  223.             printoption(">RCVD", will, c, !hisopts[c]);
  224.             /* if (c == TELOPT_TM) {
  225.                 if (flushout) {
  226.                     flushout = 0;
  227.                     }
  228.                 }
  229.             else  */ if (!hisopts[c]) {
  230.                     willoption(c, 1);
  231.                     }
  232.             SetIn3270();
  233.             telrcv_state = TS_DATA;
  234.             continue;
  235.  
  236.         case TS_WONT:
  237.             printoption(">RCVD", wont, c, hisopts[c]);
  238.             /* if (c == TELOPT_TM) {
  239.                 if (flushout) {
  240.                     flushout = 0;
  241.                     }
  242.                 }
  243.             else */  if (hisopts[c]) {
  244.                 wontoption(c, 1);
  245.                 }
  246.             SetIn3270();
  247.             telrcv_state = TS_DATA;
  248.             continue;
  249.  
  250.         case TS_DO:
  251.             printoption(">RCVD", doopt, c, !myopts[c]);
  252.             if (!myopts[c])
  253.             dooption(c);
  254.             SetIn3270();
  255.             telrcv_state = TS_DATA;
  256.             continue;
  257.  
  258.         case TS_DONT:
  259.             printoption(">RCVD", dont, c, myopts[c]);
  260.             if (myopts[c]) {
  261.                 myopts[c] = 0;
  262.                 sprintf(replyptr, wont, c);
  263.                 replyptr += sizeof (wont) - 2;
  264.                 /* flushline = 1; */
  265.                 /* setconnmode();     set new tty mode (maybe) */
  266.                 printoption(">SENT", wont, c, 0);
  267.                 }
  268.             SetIn3270();
  269.             telrcv_state = TS_DATA;
  270.             continue;
  271.  
  272.         case TS_SB:
  273.             if (c == IAC) {
  274.                 telrcv_state = TS_SE;
  275.                 }
  276.             else {
  277.                 SB_ACCUM(c);
  278.                 }
  279.             continue;
  280.  
  281.         case TS_SE:
  282.             if (c != SE) {
  283.                 if (c != IAC) {
  284.                     SB_ACCUM(IAC);
  285.                     }
  286.                 SB_ACCUM(c);
  287.                 telrcv_state = TS_SB;
  288.                 }
  289.             else {
  290.                 SB_TERM();
  291.                 suboption();    /* handle sub-option */
  292.                 SetIn3270();
  293.                 telrcv_state = TS_DATA;
  294.                 }
  295.             continue;
  296.  
  297.         default:
  298.             break;
  299.         }
  300.     }
  301. if (quitflg) {
  302.     quitflg = 0;
  303.     return;
  304.     }
  305. if (replyptr != replybuff) {
  306.     tcpwrite(replybuff, replyptr-replybuff);
  307.         /* sends data, or ends connection if unable to send */
  308.     }
  309. }
  310.  
  311. /*VARARGS*/
  312. printoption(direction, fmt, option, what)
  313.     char *direction, *fmt;
  314.     short option, what;
  315. {
  316.     if (!cs.dblevel) return;
  317.     sprintf(showmsg, "%s ", direction+1);
  318.     putln(showmsg);
  319.     if (fmt == doopt)
  320.         fmt = "do";
  321.     else if (fmt == dont)
  322.         fmt = "dont";
  323.     else if (fmt == will)
  324.         fmt = "will";
  325.     else if (fmt == wont)
  326.         fmt = "wont";
  327.     else
  328.         fmt = "???";
  329.     if (option < (sizeof(telopts)/sizeof( telopts[0])))
  330.         sprintf(showmsg, "%s %s", fmt, telopts[option]);
  331.     else
  332.         sprintf(showmsg, "%s %d", fmt, option);
  333.     putln(showmsg);
  334.     if (*direction == '<') {
  335.         putln("\n");
  336.         return;
  337.     }
  338.     sprintf(showmsg, " (%s)\n", what ? "reply" : "don't reply");
  339.     putln(showmsg);
  340. }
  341.  
  342. willoption(option, reply)
  343.     short option, reply;
  344. {
  345.     char *fmt;
  346.  
  347.     switch (option) {
  348.  
  349.     case TELOPT_ECHO:
  350.         /*
  351.          * The following is a pain in the rear-end.
  352.          * Various IBM servers (some versions of Wiscnet,
  353.          * possibly Fibronics/Spartacus, and who knows who
  354.          * else) will NOT allow us to send "DO SGA" too early
  355.          * in the setup proceedings.  On the other hand,
  356.          * 4.2 servers (telnetd) won't set SGA correctly.
  357.          * So, we are stuck.  Empirically (but, based on
  358.          * a VERY small sample), the IBM servers don't send
  359.          * out anything about ECHO, so we postpone our sending
  360.          * "DO SGA" until we see "WILL ECHO" (which 4.2 servers
  361.          * DO send).
  362.          */
  363.         {
  364.         if (askedSGA == 0) {
  365.             askedSGA = 1;
  366.             if (!hisopts[TELOPT_SGA]) {
  367.             willoption(TELOPT_SGA, 0);
  368.             }
  369.         }
  370.         }
  371.         /* Fall through */
  372.     case TELOPT_EOR:
  373.     case TELOPT_BINARY:
  374.     case TELOPT_SGA:
  375.     case TELOPT_3270:
  376.         /* settimer(modenegotiated); */
  377.         hisopts[option] = 1;
  378.         fmt = doopt;
  379.         /* setconnmode();        possibly set new tty mode */
  380.         break;
  381.  
  382.     case TELOPT_TM:
  383.         return;            /* Never reply to TM will's/wont's */
  384.  
  385.     default:
  386.         fmt = dont;
  387.         break;
  388.     }
  389.     sprintf(replyptr, fmt, option);
  390.     replyptr += sizeof (dont) - 2;
  391.     if (reply)
  392.         printoption(">SENT", fmt, option, reply);
  393.     else
  394.         printoption("<SENT", fmt, option, reply);
  395. }
  396.  
  397. wontoption(option, reply)
  398.     short option, reply;
  399. {
  400.     char *fmt;
  401.  
  402.     switch (option) {
  403.  
  404.      case TELOPT_BINARY:        /* added for Mac tn3270 */
  405.     case TELOPT_ECHO:
  406.     case TELOPT_SGA:
  407.     case TELOPT_3270:
  408.         /* settimer(modenegotiated); */
  409.         hisopts[option] = 0;
  410.         fmt = dont;
  411.         /* setconnmode();             Set new tty mode */
  412.         break;
  413.  
  414.     case TELOPT_TM:
  415.         return;        /* Never reply to TM will's/wont's */
  416.  
  417.     default:
  418.         fmt = dont;
  419.     }
  420.     sprintf(replyptr, fmt, option);
  421.     replyptr += sizeof (doopt) - 2;
  422.     if (reply)
  423.         printoption(">SENT", fmt, option, reply);
  424.     else
  425.         printoption("<SENT", fmt, option, reply);
  426. }
  427.  
  428. dooption(option)
  429.     short option;
  430. {
  431.     char *fmt;
  432.  
  433.     switch (option) {
  434.  
  435.     case TELOPT_TM:
  436.         fmt = will;
  437.         break;
  438.  
  439.     case TELOPT_EOR:
  440.     case TELOPT_BINARY:
  441.     case TELOPT_TTYPE:        /* terminal type option */
  442.     case TELOPT_SGA:        /* no big deal */
  443.     case TELOPT_3270:        /* what we're here for */
  444.         fmt = will;
  445.         myopts[option] = 1;
  446.         break;
  447.  
  448.     case TELOPT_ECHO:        /* We're never going to echo... */
  449.     default:
  450.         fmt = wont;
  451.         break;
  452.     }
  453.     sprintf(replyptr, fmt, option);
  454.     replyptr += sizeof (doopt) - 2;
  455.     printoption(">SENT", fmt, option, 0);
  456. }
  457.  
  458. /*
  459.  * suboption()
  460.  *
  461.  *    Look at the sub-option buffer, and try to be helpful to the other
  462.  * side.
  463.  *
  464.  *    Currently we recognize:
  465.  *
  466.  *        Terminal type, send request.
  467.  */
  468.  
  469. suboption()
  470. {
  471. char * usertype;
  472. short usersize;
  473. unsigned char getmodel();
  474. char sess_ext3270;
  475.  
  476. if (apiopen) {
  477.     sess_ext3270 = (apiopenreq.nowsf == 0);
  478.     }
  479. else {
  480.     sess_ext3270 = cs.ext3270;
  481.     }
  482.  
  483.     printsub("<", subbuffer, subend-subbuffer+1);
  484.     switch (subbuffer[0]&0xff) {
  485.         case TELOPT_TTYPE:
  486.             if ((subbuffer[1]&0xff) == TELQUAL_SEND) {
  487.                 /* check for a specific type the user specified after
  488.                    the host name. */
  489.                 usertype = tcphostname;
  490.                 while ((*usertype != '\0') && (*usertype != ':')) usertype++;
  491.                 if (*usertype == ':') {
  492.                     usertype++;
  493.                     usersize = 0;
  494.                     while ((usertype[usersize] != '\0') &&
  495.                            (usertype[usersize] != ':')) usersize++;
  496.                     if (usersize > 0) {
  497.                         movmem(sb_terminal, replyptr, 4);
  498.                         movmem(usertype, replyptr+4, usersize);
  499.                         movmem(sb_terminal+14, replyptr+4+usersize, 2);
  500.                         printsub(">", replyptr+2, 4+usersize);
  501.                         replyptr += usersize + 6;
  502.                         if (strncmp(usertype, "IBM-327", 7) == 0)
  503.                             sent3270tt = 1;
  504.                         return;
  505.                         }
  506.                     }
  507.  
  508.                 /*
  509.                 * Try to send a 3270 type terminal name.  Decide which one based
  510.                  * on the format of our screen, color capabilities, whether
  511.                  * we should support extended data streams, and whether we are
  512.                 * sending the first or a subsequent terminal name.
  513.                  */
  514.  
  515.                 /* Use 3278 unless color is available.
  516.                    With color, use 3279 unless extended datastream support
  517.                    is not wanted (sess_ext3270 = 0) and we already tried sending
  518.                    3279 previously (sent3270tt = 1)                         */
  519.  
  520.                 if (colormac && !((!sess_ext3270) && sent3270tt)) {
  521.                     sb_terminal[SBTERMTYPE] = '9';
  522.                     sb_e_terminal[SBTERMTYPE] = '9';
  523.                     }
  524.                 else {
  525.                     sb_terminal[SBTERMTYPE] = '8';
  526.                     sb_e_terminal[SBTERMTYPE] = '8';
  527.                     }
  528.                     
  529.                 /* set model number */
  530.                 
  531.                 sb_terminal[SBTERMMODEL] = 
  532.                                 getmodel(ses_altrows, ses_altcols) & 0x0f;
  533.                 sb_terminal[SBTERMMODEL] += 0x30;
  534.                 sb_e_terminal[SBTERMMODEL] = sb_terminal[SBTERMMODEL];
  535.                 
  536.                 /* For model 4 and 5, always use 3278, since there are no
  537.                    real 3279-4 and 3279-5 terminals.  The VM logical device
  538.                    facility rejects 3279-4 and 3279-5, even though VM TCP/IP
  539.                    accepts them (yes, it's a bug). */
  540.  
  541.                  if ((sb_terminal[SBTERMMODEL] == '4') ||
  542.                       (sb_terminal[SBTERMMODEL] == '5')) {
  543.                     sb_e_terminal[SBTERMTYPE] = sb_terminal[SBTERMTYPE] ='8';
  544.                     }
  545.  
  546.                 /* Append "-E" to terminal type unless extended datastream
  547.                    support is not wanted (sess_ext3270 = 0) or a previous
  548.                    terminal type ending with "-E" was possibly rejected 
  549.                    (sent3270tt = 1).                                        */
  550.                    
  551.                 if (sess_ext3270 && (!sent3270tt)) {
  552.                     movmem(sb_e_terminal, replyptr, sizeof(sb_e_terminal));
  553.                     printsub(">", replyptr+2, sizeof(sb_e_terminal)-2);
  554.                     replyptr += sizeof(sb_e_terminal);
  555.                     }
  556.                 else {
  557.                     movmem(sb_terminal, replyptr, sizeof(sb_terminal));
  558.                     printsub(">", replyptr+2, sizeof(sb_terminal)-2);
  559.                     replyptr += sizeof(sb_terminal);
  560.                     }
  561.  
  562.                 sent3270tt = 1;
  563.                 return;
  564.                 }
  565.     default:
  566.             break;
  567.     }
  568. }
  569.  
  570. SetIn3270()
  571. {
  572. GrafPtr gp;
  573. char do3270;
  574.  
  575.     data_init = 1;        /* reset data flag after negotiation */
  576.  
  577.     if (!newserver) {
  578.         newserver = (myopts[TELOPT_3270] != 0) ||
  579.                     (hisopts[TELOPT_3270] != 0);
  580.         }
  581.  
  582.     if (newserver) {
  583.         do3270 = (myopts[TELOPT_3270] /* && hisopts[TELOPT_3270] */);
  584.         }
  585.     else {
  586.         do3270 = (sent3270tt && myopts[TELOPT_BINARY]
  587.                 && hisopts[TELOPT_BINARY] /* && !donebinarytoggle */);
  588.         }
  589.  
  590.     if (do3270) {
  591.         if (!logon) {
  592.             EnableItem(myMenus[4], 0);    /* enable fkey menu */
  593.             DrawMenuBar();
  594.             pend_conn = 0;
  595.             logon = 1;
  596.             newstat();
  597.             }
  598.         }
  599.     else {
  600.         if (logon) {
  601.             hadascii = 1;
  602.             pend_conn = 3;
  603.             logon = 0;
  604.             skiplf = escmode = 0;
  605.             DisableItem(myMenus[4], 0);
  606.             DrawMenuBar();
  607.             kblock = aplmode = insmode = 0;
  608.             fixbracket = cs.std_brack && (!aplmode) && (stdfont != ALAFONT);
  609.             kblcode = 0;
  610.             tcpinv = 0;
  611.             newstat();
  612.             clrscn();
  613.             invldscr();
  614.             }
  615.         }
  616. }
  617.  
  618. printsub(direction, pointer, length)
  619. char    *direction,        /* "<" or ">" */
  620.     *pointer;        /* where suboption data sits */
  621. short    length;        /* length of suboption data */
  622. {
  623.     if (cs.dblevel) {
  624.     sprintf(showmsg, "%s suboption ",
  625.                 (direction[0] == '<')? "Received":"Sent");
  626.     putln(showmsg);
  627.     switch (pointer[0]) {
  628.     case TELOPT_TTYPE:
  629.         sprintf(showmsg, "Terminal type ");
  630.         putln(showmsg);
  631.         switch (pointer[1]) {
  632.         case TELQUAL_IS:
  633.         {
  634.             char tmpbuf[sizeof(subbuffer)];
  635.             short minlen;
  636.  
  637.             if (length > 3) length -= 3;
  638.             if (length < sizeof(tmpbuf)) minlen = length;
  639.             else minlen = sizeof(tmpbuf);
  640.  
  641.              movmem(pointer+2, tmpbuf, minlen);
  642.             tmpbuf[minlen-1] = 0;
  643.             sprintf(showmsg, "is %s.\n", tmpbuf);
  644.             putln(showmsg);
  645.         }
  646.         break;
  647.         case TELQUAL_SEND:
  648.         sprintf(showmsg, "- request to send.\n");
  649.         putln(showmsg);
  650.         break;
  651.         default:
  652.         sprintf(showmsg,
  653.                 "- unknown qualifier %d (0x%x).\n", pointer[1]);
  654.         putln(showmsg);
  655.         }
  656.         break;
  657.     default:
  658.         sprintf(showmsg, "Unknown option %d (0x%x)\n",
  659.                     pointer[0], pointer[0]);
  660.         putln(showmsg);
  661.     }
  662.     }
  663. }
  664.  
  665. tcpdata(sptr, slen, init, end)
  666. unsigned char * sptr;
  667. short slen;
  668. char init, end;
  669. {
  670. static char wsfflag;
  671. static unsigned char * wsfptr;
  672. static short wsfleft;
  673. short wsflen;
  674. static short xtralen, xtrainit;
  675. static char xtradata[64];
  676. unsigned char * dataptr;
  677. short datalen;
  678. static unsigned char lstopcd;
  679. static unsigned char wsfop;
  680. static char needtoend;
  681. char dbstr[64];
  682. char winit;
  683.  
  684. if (cs.dblevel > 2) {
  685.     sprintf(dbstr, "tcpdata: len = %d, init = %d, end = %d",
  686.                     slen, init, end);
  687.     putln(dbstr);
  688.     }
  689.  
  690. if (apiopenpend) {
  691.     apiregister(1);            /* register session */
  692.     if (!logon) {
  693.         apiopenresp(openLineMode);
  694.         }
  695.     else {
  696.         apiopenresp(open3270Mode);
  697.         }
  698.     }
  699.     
  700. if (!logon) {
  701.     if (kblock) {
  702.         kblock = 0;
  703.         newstat();
  704.         }
  705.     hadascii = 1;
  706.     if (servermode) putsrv(sptr, slen, 0);
  707.     else putscr(sptr, slen, 0);
  708.     writeresponse(0);
  709.     return;
  710.     }
  711.  
  712. /* length 0 valid only if init==0 and end==1 */
  713. if ((slen == 0) && (init || (!end))) return;
  714.  
  715. if (init) {
  716.     wsfflag = ((sptr[0] == 0x11) || (sptr[0] == 0xf3)); 
  717.     if (wsfflag) {
  718.         wsfptr = wsfbuff;
  719.         wsfleft = 8192;
  720.         wsfop = sptr[0];
  721.         }
  722.     }
  723.  
  724. if (wsfflag) {
  725.     /* if ((init) && (end)) {
  726.         if (cs.dblevel > 1) tcpdump("writesf", sptr, slen);
  727.         writesf(sptr, slen, 1);        
  728.         writeresponse(wsfop);
  729.         return;
  730.         }    */    /* must copy data for vmxfer compression code */
  731.     if (slen > 0) {
  732.         if (slen > wsfleft) wsflen = wsfleft;
  733.         else wsflen = slen;
  734.         movmem(sptr, wsfptr, wsflen);
  735.         wsfleft -= wsflen;
  736.         wsfptr += wsflen;
  737.         }
  738.     if (end) { 
  739.         /* invldscr(); */
  740.         if (cs.dblevel > 1) tcpdump("writesf", wsfbuff, wsfptr-wsfbuff);
  741.         writesf(wsfbuff, wsfptr-wsfbuff, 1);
  742.         writeresponse(wsfop);
  743.         }
  744.     return;
  745.     }
  746.  
  747. if (init) {
  748.     lstopcd = sptr[0];
  749.     xtralen =  xtrainit = 0;
  750.     needtoend = 0;
  751.     }
  752.  
  753. switch (lstopcd) {
  754.     case 0x01:                    /* write */
  755.     case 0x05:                    /* erase/write */
  756.     case 0x0d:                    /* erase/write alt. */
  757.     case 0xf1:                    /* SNA write */
  758.     case 0xf5:                    /* SNA erase/write */
  759.     case 0x7e:                    /* SNA erase/write alt. */
  760.             if (init && (slen == 1)) {        /* just op-code */
  761.                 xtralen = 1;                /* save op-code until wcc */
  762.                 xtradata[0] = sptr[0];
  763.                 xtrainit = 1;
  764.                 break;
  765.                 }
  766.             if (slen > 0) {
  767.                 needtoend = 1;
  768.                 if (xtralen > 0)
  769.                     movmem(xtradata, sptr-xtralen, xtralen);
  770.                 ldvoff = 0;
  771.                 dataptr = sptr-xtralen;
  772.                 datalen = slen + xtralen;
  773.                 if (xtrainit) winit = 1;
  774.                 else winit = init;
  775.                 if (cs.dblevel > 1) {
  776.                     sprintf(dbstr, "writetm: init = %d", winit);
  777.                     tcpdump(dbstr, dataptr, datalen);
  778.                     }
  779.                 writetm(dataptr, datalen, winit);
  780.                 xtralen = datalen - ldvoff;
  781.                 xtrainit = 0;
  782.                 if (xtralen == 0) break;
  783.                 if (xtralen > 64) xtralen = 64;
  784.                 movmem(dataptr+ldvoff, xtradata, xtralen);
  785.                 }
  786.             break;
  787.     case 0x0f:                    /* erase all unprot. */
  788.     case 0x6f:                    /* SNA erase all unprot. */
  789.             if (!init) return;
  790.             funckey(10);
  791.             rdaid = 60;
  792.             writeresponse(lstopcd);
  793.             return;
  794.     case 0x06:                    /* read modified */
  795.     case 0xf6:                    /* SNA read modified */
  796.             if (!init) return;
  797.             rdmcmd(rdaid);
  798.             writeresponse(lstopcd);
  799.             return;
  800.     case 0x6e:                    /* SNA read modified all */
  801.             if (!init) return;
  802.             rdmacmd(rdaid);
  803.             writeresponse(lstopcd);
  804.             return;
  805.     case 0x02:                    /* read buffer */
  806.     case 0xf2:                    /* SNA read buffer */
  807.             if (!init) return;
  808.             rdbuff();
  809.             writeresponse(lstopcd);
  810.             return;
  811.     default:
  812.             return;
  813.     }
  814.  
  815. if (end) {
  816.     if (needtoend) {
  817.         endwcc();    /* sets pndbeep if beep needed */
  818.         writeresponse(lstopcd);
  819.         needtoend = 0;
  820.         }
  821.     tcpinv = 1;        /* tcpevent will call invldscr and possibly beep */
  822.     }
  823. }
  824.  
  825. tcpkbin(asc, chr, shift)        /* handle new character in line mode */
  826. unsigned char asc, chr, shift;
  827. {
  828. static unsigned char nl[2] = {0x0d, 0x0a};
  829. static unsigned char brk[2] = {0xff, 0xf3};
  830. static unsigned char del[2] = {0xff, 0xf7};
  831. static unsigned char up[2] = {0x1b, 0x41};
  832. static unsigned char down[2] = {0x1b, 0x42};
  833. static unsigned char right[2] = {0x1b, 0x43};
  834. static unsigned char left[2] = {0x1b, 0x44};
  835. static unsigned char pf1[3] = {0x1b, 0x4f, 0x50};
  836. static unsigned char pf2[3] = {0x1b, 0x4f, 0x51};
  837. static unsigned char pf3[3] = {0x1b, 0x4f, 0x52};
  838. static unsigned char pf4[3] = {0x1b, 0x4f, 0x53};
  839. unsigned char c, typ, val;
  840.  
  841. switch(chr) {
  842.     case 190:                /* "rub-out" function */
  843.         tcpwrite(del, 2);
  844.         break;
  845.     case 170:                /* "clear" function */
  846.         tcpwrite(brk, 2);
  847.         break;
  848.     case 142:                /* "enter" function */
  849.         tcpwrite(nl, 2);
  850.         break;
  851.     case 175:                /* "left" function */
  852.         c = 0x08;                /* send normal backspace */
  853.         tcpwrite(&c, 1);
  854.         break;
  855.     case 143:                /* "pf1" function */
  856.         tcpwrite(pf1, 3);
  857.         break;
  858.     case 144:                /* "pf2" function */
  859.         tcpwrite(pf2, 3);
  860.         break;
  861.     case 145:                /* "pf3" function */
  862.         tcpwrite(pf3, 3);
  863.         break;
  864.     case 146:                /* "pf4" function */
  865.         tcpwrite(pf4, 3);
  866.         break;
  867.     case 173:                /* "up" function */
  868.         tcpwrite(up, 2);
  869.         break;
  870.     case 174:                /* "down" function */
  871.         tcpwrite(down, 2);
  872.         break;
  873.     case 184:                /* "delete-char" function */
  874.         tcpwrite(left, 2);
  875.         break;
  876.     case 176:                /* "right" function */
  877.         tcpwrite(right, 2);
  878.         break;
  879.     default:
  880.         if (asc > 127) return;
  881.         c = asc;
  882.         tcpwrite(&c, 1);
  883.         break;
  884.     }
  885. }
  886.